#include "common.h"
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

boost::property_tree::ptree settings;
void append(std::vector<unsigned char>& dest,const std::vector<unsigned char>& src){
    dest.insert(dest.end(),std::make_move_iterator(src.begin()),std::make_move_iterator(src.end()));
}
void rappend(std::vector<unsigned char>& dest,const std::vector<unsigned char>& src){
    dest.insert(dest.begin(),std::make_move_iterator(src.begin()),std::make_move_iterator(src.end()));
}
void append(std::vector<unsigned char>& dest,const std::vector<unsigned char>& src, size_t len){
    dest.insert(dest.end(),std::make_move_iterator(src.begin()),std::make_move_iterator(src.begin()+len));
}
void rappend(std::vector<unsigned char>& dest,const std::vector<unsigned char>& src, size_t len){
    dest.insert(dest.begin(),std::make_move_iterator(src.begin()),std::make_move_iterator(src.begin()+len));
}
unsigned char bitcombine(std::vector<int64_t>::iterator its,std::vector<int64_t>::iterator ite){
    unsigned char ret=0;
    auto itstart = its;
    for(;its!=ite;++its){
        ret|=1<<(std::distance(itstart,its));
    }
    return ret;
}
std::vector<unsigned char> bitsplit(std::vector<int64_t>&item, int len){
    std::vector<unsigned char> ret;
    if(item.size()<len){
        for(int i=0;i<item.size();++i){
            for(int j=1;j<=len/item.size();++j){
                size_t offset = (len/item.size()-j)*8;
                ret.emplace_back((item[i]&(0xff<<offset))>>offset);
            }
        }
        if(ret.size()==len)
            return ret;
        return std::vector<unsigned char>();
    }else if(item.size()==len){
        std::for_each(item.begin(),item.end(),[&](auto it){ret.emplace_back(it);});
        return ret;
    }else{
        return ret;
    }
}
std::vector<unsigned char> config_parse(std::string label,std::string stext, int len){
    std::vector<unsigned char> config;
    if(!stext.empty()){
        int64_t num;
        std::vector<int64_t> nums;
        std::stringstream ss(stext);
        while(ss>>std::hex>>num) nums.emplace_back(num);
        switch(len){
            case 1:{
                if(nums.size()==1){
                    config.emplace_back(nums[0]);
                }else{
                    BOOST_LOG_TRIVIAL(info)<<"parse no found,"<<label;
                    return config;
                }
                break;
            }
            case 2:{
                if(nums.size()<=8){
                    config.emplace_back(0);
                    config.emplace_back(bitcombine(nums.begin(),nums.end()));
                }else if(nums.size()>8){
                    config.emplace_back(bitcombine(nums.begin()+8,nums.end()));
                    config.emplace_back(bitcombine(nums.begin(),nums.begin()+8));
                }else{
                    BOOST_LOG_TRIVIAL(info)<<"parse no found,"<<label;
                    return config;
                }
                break;
            }
            case 4:{
                config = bitsplit(nums,4);
                if(!config.size()) {
                    BOOST_LOG_TRIVIAL(info)<<"parse error,"<<label;
                    return config;
                }
                break;
            }
            case 8:{
                config = bitsplit(nums,8);
                if(!config.size()){
                    BOOST_LOG_TRIVIAL(info)<<"parse error,"<<label;
                    return config;
                }
                break;
            }
            case 24:{
                config = bitsplit(nums,24);
                if(!config.size()){
                    BOOST_LOG_TRIVIAL(info)<<"parse error,"<<label;
                    return config;
                }
                break;
            }
            default:{
                BOOST_LOG_TRIVIAL(info)<<"parse no found,"<<label;
                break;
            }
        }
    }
    return config;
}
void init_binary_log(std::string filename, int time, size_t max_size)
{
    auto textBackend = boost::make_shared<boost::log::sinks::text_ostream_backend>();
    textBackend->add_stream(boost::shared_ptr<std::ostream>(&std::cout, [](std::ostream*) {}));
    auto textSink = boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>>(textBackend);
    textSink->set_filter(boost::log::trivial::severity > boost::log::trivial::trace);
    boost::log::core::get()->add_sink(textSink);

    auto binaryBackend = boost::make_shared<boost::log::sinks::text_file_backend>(
        boost::log::keywords::time_based_rotation = 
                boost::log::sinks::file::rotation_at_time_interval(boost::posix_time::minutes(time)),
            boost::log::keywords::file_name=filename,
            boost::log::keywords::target_file_name = filename.substr(0,filename.find('.'))+"_%5N.bin",
            boost::log::keywords::max_size = max_size * 1024 * 1024,
            boost::log::keywords::open_mode=std::ios::binary
    );
    auto binarySink = boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend>>(binaryBackend);
    binarySink->set_formatter([](const boost::log::record_view& rec, boost::log::formatting_ostream& strm) {
        const char* binary_data = rec[boost::log::expressions::smessage].get().data();
        std::streamsize size = rec[boost::log::expressions::smessage].get().size();
        strm.write(binary_data, size);
    });
    binarySink->set_filter(boost::log::trivial::severity == boost::log::trivial::trace);
    boost::log::core::get()->add_sink(binarySink);
    boost::log::add_common_attributes();
}

#ifdef _WIN32
#include <windows.h>
void set_thread_priority(std::thread& t, int priority) {
    HANDLE native_handle = t.native_handle();
    SetThreadPriority(native_handle, priority);
}
#else
#include <pthread.h>
void set_thread_priority(std::thread& t, int priority) {
    pthread_t native_handle = t.native_handle();
    sched_param sch_params;
    sch_params.sched_priority = priority;
    pthread_setschedparam(native_handle, SCHED_FIFO, &sch_params);
}
#endif